package game_engine.core;

import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glTranslatef;
import static org.lwjgl.opengl.GL11.glVertex2f;

import game_engine.display.Texture;

import java.awt.Image;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;


public abstract class Entity {
	
	protected Vector2f position;
	protected Vector2f direction = new Vector2f(0, 0);
	private ArrayList<Vector2f> allDirection = new ArrayList<Vector2f>();
	private float[] rotations;
	private int[] rotationsTiming;
	private boolean rotationsLoop;
	private int lastRotationTick;
	protected int currentRotation;
	private float speed = 5.0f;
	
	protected Rectangle2D boundingBox;
	protected Texture[][] frames;
	protected int[][] frameCount;
	protected boolean[] frameLoop;
	protected int currentFrame;
	protected int currentAction = -1;
	private int lastAction = -1;
	private long lastFrameTick = 0;
	
	protected float tick;
	
	protected String name;
	protected int value = 0;
	
	protected boolean unspawning = false;
	protected boolean dead = false;
	
	public Entity(String name) {
		this.name = name;
	}
	
	public Entity() {
		this("no_name");
	}
		
	public Entity(Rectangle2D boundingBox, Texture[][] frames) {
		this.boundingBox = boundingBox;
		this.frames = frames;
	}
	
	public void move(long tick) {
		float x = normalize(direction).x;
		float y = normalize(direction).y;
		if(rotations!=null) {
			if(rotationsLoop){
				if(rotationsTiming[currentRotation]<lastRotationTick) {
					currentRotation = (currentRotation+1)%rotations.length;
					lastRotationTick = 0;
				} else 
					lastRotationTick += tick;
			} else {
				if(currentRotation!=rotations.length-1)  {
					if(rotationsTiming[currentRotation]<lastRotationTick){
						currentRotation++;
						lastRotationTick = 0;
					} else
						lastRotationTick += tick;
				}
			}
			direction.x = (float) ((x*Math.cos(rotations[currentRotation] * tick * 0.4/1000) - y*Math.sin(rotations[currentRotation] * tick * 0.4/1000)));
			direction.y = (float) ((x*Math.sin(rotations[currentRotation] * tick * 0.4/1000) + y*Math.cos(rotations[currentRotation] * tick * 0.4/1000)));
		}
		position.x += direction.x * tick * speed;
		position.y += direction.y * tick * speed;
	}
	
	private Vector2f normalize(Vector2f vector) {
		float norm = (float) Math.sqrt(vector.x*vector.x + vector.y*vector.y);
		return new Vector2f(vector.x/norm, vector.y/norm);
	}
	
	public Vector2f getPosition() {
		return position;
	}
	
	public void setPosition(Vector2f position) {
		this.position = position;
	}
	
	public Vector2f getDirection() {
		return direction;
	}
	
	public void setDirection(Vector2f direction) {
			this.direction = direction;
	}
	
	public void addSpeed(Vector2f speed) {
		synchronized (allDirection) {
			if(!allDirection.contains(speed))
				allDirection.add(speed);			
		}		
		updateDirection();
	}
	
	private void updateDirection() {
		this.direction = new Vector2f(0, 0);
		synchronized (allDirection) {
			for(Vector2f s : allDirection) {
				this.direction.x += s.x;
				this.direction.y += s.y;
			}	
		}
	}
	
	public void updateAnimation(long tick) {
		long start = System.nanoTime();
		if(currentAction!=-1) {
			if(frameCount[currentAction].length>currentFrame) {
				if(frameCount[currentAction][currentFrame]<lastFrameTick) {
					if(frameLoop[currentAction]){
						currentFrame = (currentFrame+1)%frames[currentAction].length;
					}
					else 
						if(currentFrame!=frames[currentAction].length-1) {
							currentFrame++;
						}
					lastFrameTick = 0;
				} else {
					lastFrameTick += tick;
				}
			} else
				System.err.println("currentFrame is wrong : " + currentFrame + "/" + frameCount[currentAction].length + " on action : " + currentAction);
		}
		long time = System.nanoTime() - start;
		if(time>500000)System.out.println("Single animation : " + (double)time/1000000 + "ms.");
	}
	
	public float getSpeed() {
		return speed;
	}
	
	public void setSpeed(float speed) {
		this.speed = speed;
	}
	
	public abstract void collided(Entity e);
	public abstract void doAction(float tick);
	
	public void removeSpeed(Vector2f speed) {
		synchronized (allDirection) {
			allDirection.remove(speed);	
		}
		updateDirection();
	}
	
	public Rectangle2D getBox() {
		return boundingBox;
	}
	
	public void setBox(Rectangle2D box) {
		boundingBox = box;
	}
	
	public abstract void render();
	
	@Override
	public String toString() {
		return name;
	}
	
//	public abstract void unSpawn();
	
	public boolean isUnspawning() {
		return unspawning;
	}
	
	public boolean isDead() {
		return dead;
	}

	public void setFrames(Texture[][] frames) {
		this.frames = frames;
	}

	public void setFrameCount(int[][] frameCount) {
		this.frameCount = frameCount;
	}
	
	public void setFrameLoop(boolean[] frameLoop) {
		this.frameLoop = frameLoop;
	}
	
	public int getCurrentAction() {
		return currentAction;
	}
	
	public void setCurrentAction(int currentAction) {
		if(lastAction!=currentAction) {
			this.currentFrame = 0;
			lastAction = currentAction;
		}
		this.currentAction = currentAction;
	}
	
	public Texture[][] getFrames() {
		return frames;
	}
	
	public int[][] getFrameCount() {
		return frameCount;
	}
	
	public int getCurrentFrame() {
		return currentFrame;
	}

	public void setRotations(float[] rotations) {
		this.rotations = rotations;
	}

	public void setRotationsTiming(int[] rotationsTiming) {
		this.rotationsTiming = rotationsTiming;
	}

	public void setRotationsLoop(boolean rotationsLoop) {
		this.rotationsLoop = rotationsLoop;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}
